package com.dag.account.service.impl;

import com.dag.account.api.dto.payment.*;
import com.dag.account.constants.*;
import com.dag.account.dao.entity.Account;
import com.dag.account.dao.entity.Member;
import com.dag.account.dao.entity.TradeRecord;
import com.dag.account.service.*;
import com.dag.account.utils.TradeUtils;
import com.dag.common.exception.BusinessRuntimeException;
import com.dag.common.utils.IDataUtils;
import com.dag.common.utils.ModelMapperUtils;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;

/**
 * 付款管理
 * @author 孙建
 * @since 2020-06-01
 */
@Slf4j
@Service
public class PaymentServiceImpl implements IPaymentService {

    @Autowired
    private IMemberService memberService;
    @Autowired
    private ITradeRecordService tradeRecordService;
    @Autowired
    private IFundPoolService fundPoolService;
    @Autowired
    private IPlatformService platformService;
    @Autowired
    private IAccountService accountService;

    /**
     * 统一支付
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public UnifiedPayRespDTO unifiedPay(UnifiedPayReqDTO payRequestDTO) {
        String draweeMemberId = payRequestDTO.getDraweeMemberId();
        Integer accountType = payRequestDTO.getAccountType();
        String operatorName = payRequestDTO.getOperatorName();
        // 付款人和付款账户
        Account draweeAccount = accountService.queryByMemberIdAndAccountType(draweeMemberId, accountType);
        Member draweeMember = memberService.getById(draweeMemberId);
        // 收款人和收款账户
        Account platformAccount = platformService.queryPlatformAccount();
        Member platformMember = platformService.queryPlatformMember();

        // 校验账户
        UnifiedPayRespDTO payResponseDTO = validateUnifiedPay(payRequestDTO, draweeAccount);
        // 校验通过
        if(payResponseDTO.isSuccess()){
            BigDecimal payAcount = payRequestDTO.getAmount();
            // 付款账户减钱
            accountService.deduction(draweeAccount, payAcount, operatorName);
            // 平台账户加钱
            accountService.add(platformAccount, payAcount, operatorName);
            // 保存付款交易记录
            TradeRecord tradeRecord = new TradeRecord();
            tradeRecord.setSerialNo(TradeUtils.buildSeqNo());
            tradeRecord.setTradeVoucherNo(payRequestDTO.getTradeVoucherNo());
            tradeRecord.setAccountId(draweeAccount.getId());
            tradeRecord.setMemberId(draweeMember.getId());
            tradeRecord.setMemberName(draweeMember.getMemberName());
            tradeRecord.setOtherMemberId(platformMember.getId());
            tradeRecord.setOtherMemberName(platformMember.getMemberName());
            tradeRecord.setOtherAccountId(platformAccount.getId());
            tradeRecord.setTradeType(TradeTypeEnum.PAYED.getIndex());
            tradeRecord.setTradeTypeName(TradeTypeEnum.PAYED.getText());
            tradeRecord.setAmount(payAcount.abs().multiply(BigDecimal.valueOf(-1)));
            tradeRecord.setTradeChannel(TradeChannelEnum.ACCOUNT.getIndex());
            tradeRecord.setTradeSubject(payRequestDTO.getTradeSubject());
            tradeRecord.setTradeContent(payRequestDTO.getTradeContent());
            tradeRecord.setFundFlowType(FundFlowTypeEnum.PAY.getIndex());
            tradeRecord.setTradeStatus(TradeStatusEnum.TRADE_STATUS_SUCCESS.getIndex());
            tradeRecord.setTradeTime(new Date());
            tradeRecord.setCreateTime(new Date());
            tradeRecord.setOrgId(platformAccount.getOrgId());
            tradeRecord.setMerchantId(platformAccount.getMerchantId());
            // 生成平台交易记录
            TradeRecord otherTradeRecord = TradeUtils.copyAndReverse(tradeRecord);
            tradeRecordService.saveBatch(Lists.newArrayList(tradeRecord, otherTradeRecord));

            // 支付成功返回信息
            payResponseDTO.setSerialNo(tradeRecord.getSerialNo());
            payResponseDTO.setAmount(payAcount);
            payResponseDTO.setMessage("支付成功");
        }
        return payResponseDTO;
    }

    /**
     * 账户冻结预支付
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public FreezePrePayRespDTO freezePrePay(FreezePrePayReqDTO freezePrePayReqDTO) {
        String draweeMemberId = freezePrePayReqDTO.getDraweeMemberId();
        Integer accountType = freezePrePayReqDTO.getAccountType();
        String operatorName = freezePrePayReqDTO.getOperatorName();
        // 付款人和付款账户
        Account draweeAccount = accountService.queryByMemberIdAndAccountType(draweeMemberId, accountType);
        Member draweeMember = memberService.getById(draweeMemberId);
        // 收款人和收款账户
        Account platformAccount = platformService.queryPlatformAccount();
        Member platformMember = platformService.queryPlatformMember();

        // 校验账户
        FreezePrePayRespDTO freezePrePayRespDTO = validateFreezePrePay(freezePrePayReqDTO, draweeAccount);
        // 校验通过
        if(freezePrePayRespDTO.isSuccess()){
            BigDecimal freezeAcount = freezePrePayReqDTO.getAmount();
            // 付款账户减钱
            accountService.freeze(draweeAccount, freezeAcount, operatorName);
            // 保存冻结支付交易记录
            TradeRecord tradeRecord = new TradeRecord();
            tradeRecord.setSerialNo(TradeUtils.buildSeqNo());
            tradeRecord.setTradeVoucherNo(freezePrePayReqDTO.getTradeVoucherNo());
            tradeRecord.setAccountId(draweeAccount.getId());
            tradeRecord.setMemberId(draweeMember.getId());
            tradeRecord.setMemberName(draweeMember.getMemberName());
            tradeRecord.setOtherMemberId(platformMember.getId());
            tradeRecord.setOtherMemberName(platformMember.getMemberName());
            tradeRecord.setOtherAccountId(platformAccount.getId());
            tradeRecord.setTradeType(TradeTypeEnum.PAYED.getIndex());
            tradeRecord.setTradeTypeName(TradeTypeEnum.PAYED.getText());
            tradeRecord.setAmount(freezeAcount.abs().multiply(BigDecimal.valueOf(-1)));
            tradeRecord.setTradeChannel(TradeChannelEnum.ACCOUNT.getIndex());
            tradeRecord.setTradeSubject(freezePrePayReqDTO.getTradeSubject());
            tradeRecord.setTradeContent(freezePrePayReqDTO.getTradeContent());
            tradeRecord.setFundFlowType(FundFlowTypeEnum.PAY.getIndex());
            tradeRecord.setTradeStatus(TradeStatusEnum.TRADE_STATUS_TRADING.getIndex());
            tradeRecord.setTradeTime(new Date());
            tradeRecord.setCreateTime(new Date());
            tradeRecord.setOrgId(platformAccount.getOrgId());
            tradeRecord.setMerchantId(platformAccount.getMerchantId());
            // 生成平台交易记录
            TradeRecord otherTradeRecord = TradeUtils.copyAndReverse(tradeRecord);
            tradeRecordService.saveBatch(Lists.newArrayList(tradeRecord, otherTradeRecord));

            // 支付成功返回信息
            freezePrePayRespDTO.setSerialNo(tradeRecord.getSerialNo());
            freezePrePayRespDTO.setAmount(freezeAcount);
            freezePrePayRespDTO.setMessage("冻结预支付成功");
        }
        return freezePrePayRespDTO;
    }


    /**
     * 账户解冻并确认支付
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public UnfreezeConfirmPayRespDTO unfreezeConfirmPay(UnfreezeConfirmPayReqDTO unfreezeConfirmPayReqDTO) {
        String draweeMemberId = unfreezeConfirmPayReqDTO.getDraweeMemberId();
        Integer accountType = unfreezeConfirmPayReqDTO.getAccountType();
        String operatorName = unfreezeConfirmPayReqDTO.getOperatorName();
        // 付款人和付款账户
        Account draweeAccount = accountService.queryByMemberIdAndAccountType(draweeMemberId, accountType);
        // 收款人和收款账户
        Account platformAccount = platformService.queryPlatformAccount();

        // 校验账户
        UnfreezeConfirmPayRespDTO unfreezeConfirmPayRespDTO = validateUnfreezeConfirmPay(unfreezeConfirmPayReqDTO, draweeAccount);
        // 校验通过
        if(unfreezeConfirmPayRespDTO.isSuccess()){
            BigDecimal unfreezeAcount = unfreezeConfirmPayReqDTO.getAmount();
            // 付款账户解冻扣除
            accountService.unfreezeDeduction(draweeAccount, unfreezeAcount, operatorName);
            // 平台账户加钱
            accountService.add(platformAccount, unfreezeAcount, operatorName);

            // 查询之前冻结支付的记录 并且更新交易状态
            List<TradeRecord> tradeRecordList = tradeRecordService.queryByTradeVoucherNo(unfreezeConfirmPayReqDTO.getTradeVoucherNo());
            for (TradeRecord tradeRecord : tradeRecordList) {
                if(tradeRecord.getFundFlowType() == FundFlowTypeEnum.PAY.getIndex()){
                    unfreezeConfirmPayRespDTO.setSerialNo(tradeRecord.getSerialNo());
                }
                tradeRecord.setTradeStatus(TradeStatusEnum.TRADE_STATUS_SUCCESS.getIndex());
            }
            tradeRecordService.updateBatchById(tradeRecordList);

            // 支付成功返回信息
            unfreezeConfirmPayRespDTO.setAmount(unfreezeAcount);
            unfreezeConfirmPayRespDTO.setMessage("解冻并支付成功");
        }
        return unfreezeConfirmPayRespDTO;
    }


    /**
     * 账户解冻并取消支付
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public UnfreezeCancelPayRespDTO unfreezeCancelPay(UnfreezeCancelPayReqDTO unfreezeCancelPayReqDTO) {
        String draweeMemberId = unfreezeCancelPayReqDTO.getDraweeMemberId();
        Integer accountType = unfreezeCancelPayReqDTO.getAccountType();
        String operatorName = unfreezeCancelPayReqDTO.getOperatorName();
        // 付款人和付款账户
        Account draweeAccount = accountService.queryByMemberIdAndAccountType(draweeMemberId, accountType);

        // 校验账户
        UnfreezeCancelPayRespDTO unfreezeCancelPayRespDTO = validateUnfreezeCancelPay(unfreezeCancelPayReqDTO, draweeAccount);
        // 校验通过
        if(unfreezeCancelPayRespDTO.isSuccess()){
            BigDecimal unfreezeAcount = unfreezeCancelPayReqDTO.getAmount();
            // 付款账户解冻
            accountService.unfreeze(draweeAccount, unfreezeAcount, operatorName);

            // 查询之前冻结支付的记录 并且更新交易状态
            List<TradeRecord> tradeRecordList = tradeRecordService.queryByTradeVoucherNo(unfreezeCancelPayReqDTO.getTradeVoucherNo());
            for (TradeRecord tradeRecord : tradeRecordList) {
                if(tradeRecord.getFundFlowType() == FundFlowTypeEnum.PAY.getIndex()){
                    unfreezeCancelPayRespDTO.setSerialNo(tradeRecord.getSerialNo());
                }
                tradeRecord.setTradeStatus(TradeStatusEnum.TRADE_STATUS_CLOSE.getIndex());
            }
            tradeRecordService.updateBatchById(tradeRecordList);

            // 支付成功返回信息
            unfreezeCancelPayRespDTO.setAmount(unfreezeAcount);
            unfreezeCancelPayRespDTO.setMessage("解冻并取消支付成功");
        }
        return unfreezeCancelPayRespDTO;
    }



    /**
     * 支付记录
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void paymentRecord(PaymentRecordDTO paymentRecordDTO) {
        String draweeMemberId = paymentRecordDTO.getDraweeMemberId();
        BigDecimal amount = paymentRecordDTO.getAmount();
        String operatorName = paymentRecordDTO.getOperatorName();
        Member member = memberService.getById(draweeMemberId);
        if(member == null){
            throw new BusinessRuntimeException("付款会员不存在");
        }

        // 平台收款账户增加一笔
        Account platformAccount = platformService.queryPlatformAccount();
        Member platformMember = platformService.queryPlatformMember();
        accountService.add(platformAccount, amount, operatorName);

        // 资金池增加一笔
        fundPoolService.add(amount, operatorName);

        // 保存付款人交易记录
        TradeRecord tradeRecord = ModelMapperUtils.map(paymentRecordDTO, TradeRecord.class);
        tradeRecord.setSerialNo(TradeUtils.buildSeqNo());
        tradeRecord.setMemberId(paymentRecordDTO.getDraweeMemberId());
        tradeRecord.setMemberName(member.getMemberName());
        tradeRecord.setOtherMemberId(platformMember.getId());
        tradeRecord.setOtherMemberName(platformMember.getMemberName());
        tradeRecord.setOtherAccountId(platformAccount.getId());
        tradeRecord.setTradeType(TradeTypeEnum.PAYED.getIndex());
        tradeRecord.setTradeTypeName(TradeTypeEnum.PAYED.getText());
        tradeRecord.setAmount(amount.abs().multiply(BigDecimal.valueOf(-1)));
        tradeRecord.setTradeSubject(paymentRecordDTO.getTradeSubject());
        tradeRecord.setTradeContent(paymentRecordDTO.getTradeContent());
        tradeRecord.setFundFlowType(FundFlowTypeEnum.PAY.getIndex());
        tradeRecord.setCreateTime(new Date());
        tradeRecord.setOrgId(member.getOrgId());
        tradeRecord.setMerchantId(member.getMerchantId());
        // 生成平台交易记录
        TradeRecord otherTradeRecord = TradeUtils.copyAndReverse(tradeRecord);
        tradeRecordService.saveBatch(Lists.newArrayList(tradeRecord, otherTradeRecord));
    }


    /**
     * 统一支付校验
     */
    private UnifiedPayRespDTO validateUnifiedPay(UnifiedPayReqDTO payRequestDTO, Account draweeAccount) {
        String tradeVoucherNo = payRequestDTO.getTradeVoucherNo();
        if(draweeAccount == null){
            return UnifiedPayRespDTO.byFail(null, tradeVoucherNo, "付款账户不存在");
        }

        // 判断交易是否已经操作过
        TradeRecord tradeRecord = tradeRecordService.queryByTradeVoucherNo(tradeVoucherNo, TradeTypeEnum.PAYED.getIndex(),
                FundFlowTypeEnum.PAY.getIndex(), TradeStatusEnum.TRADE_STATUS_SUCCESS.getIndex());
        if(tradeRecord != null){
            return UnifiedPayRespDTO.byFail(tradeRecord.getSerialNo(), tradeVoucherNo, "交易业务单号已完成交易，请检查");
        }

        Integer draweeAccountStatus = draweeAccount.getStatus();
        if(draweeAccountStatus != AccountStatusEnum.VALID.getIndex()){
            return UnifiedPayRespDTO.byFail(null, tradeVoucherNo, "付款账户状态异常");
        }

        // 判断付款账户余额是否充足
        BigDecimal amount = payRequestDTO.getAmount();
        if(draweeAccount.getBalanceAmount().compareTo(amount) < 0){
            return UnifiedPayRespDTO.byFail(null, tradeVoucherNo, "付款账户余额不足");
        }
        return UnifiedPayRespDTO.bySuccess(null, tradeVoucherNo, "校验通过");
    }


    /**
     * 冻结预支付校验
     */
    private FreezePrePayRespDTO validateFreezePrePay(FreezePrePayReqDTO freezePrePayReqDTO, Account draweeAccount) {
        String tradeVoucherNo = freezePrePayReqDTO.getTradeVoucherNo();
        if(draweeAccount == null){
            return FreezePrePayRespDTO.byFail(null, tradeVoucherNo, "付款账户不存在");
        }

        // 判断交易是否已经操作过
        TradeRecord tradeRecord = tradeRecordService.queryByTradeVoucherNo(tradeVoucherNo, TradeTypeEnum.PAYED.getIndex(),
                FundFlowTypeEnum.PAY.getIndex(), null);
        if(tradeRecord != null){
            return FreezePrePayRespDTO.byFail(tradeRecord.getSerialNo(), tradeVoucherNo, "交易业务单号已完成交易，请检查");
        }

        Integer draweeAccountStatus = draweeAccount.getStatus();
        if(draweeAccountStatus != AccountStatusEnum.VALID.getIndex()){
            return FreezePrePayRespDTO.byFail(null, tradeVoucherNo, "付款账户状态异常");
        }

        // 判断付款账户余额是否充足
        BigDecimal amount = freezePrePayReqDTO.getAmount();
        if(draweeAccount.getBalanceAmount().compareTo(amount) < 0){
            return FreezePrePayRespDTO.byFail(null, tradeVoucherNo, "付款账户余额不足");
        }
        return FreezePrePayRespDTO.bySuccess(null, tradeVoucherNo, "校验通过");
    }


    /**
     * 解冻支付校验
     */
    private UnfreezeConfirmPayRespDTO validateUnfreezeConfirmPay(UnfreezeConfirmPayReqDTO unfreezeConfirmPayReqDTO, Account draweeAccount) {
        String tradeVoucherNo = unfreezeConfirmPayReqDTO.getTradeVoucherNo();
        if(draweeAccount == null){
            return UnfreezeConfirmPayRespDTO.byFail(tradeVoucherNo, "付款账户不存在");
        }

        // 判断交易是否已经操作过
        List<TradeRecord> tradeRecordList = tradeRecordService.queryByTradeVoucherNo(tradeVoucherNo);
        if(IDataUtils.isNotEmpty(tradeRecordList)){
            for (TradeRecord tradeRecord : tradeRecordList) {
                Integer tradeStatus = tradeRecord.getTradeStatus();
                if(tradeStatus != TradeStatusEnum.TRADE_STATUS_TRADING.getIndex()){
                    return UnfreezeConfirmPayRespDTO.byFail(tradeVoucherNo, "交易业务单号已完成交易，请检查");
                }
            }
        }

        Integer draweeAccountStatus = draweeAccount.getStatus();
        if(draweeAccountStatus != AccountStatusEnum.VALID.getIndex()){
            return UnfreezeConfirmPayRespDTO.byFail(tradeVoucherNo, "付款账户状态异常");
        }

        return UnfreezeConfirmPayRespDTO.bySuccess(tradeVoucherNo, "校验通过");
    }


    /**
     * 解冻取消支付校验
     */
    private UnfreezeCancelPayRespDTO validateUnfreezeCancelPay(UnfreezeCancelPayReqDTO unfreezeCancelPayReqDTO, Account draweeAccount) {
        String tradeVoucherNo = unfreezeCancelPayReqDTO.getTradeVoucherNo();
        if(draweeAccount == null){
            return UnfreezeCancelPayRespDTO.byFail(tradeVoucherNo, "解冻账户不存在");
        }

        // 判断交易是否已经操作过
        List<TradeRecord> tradeRecordList = tradeRecordService.queryByTradeVoucherNo(tradeVoucherNo);
        if(IDataUtils.isNotEmpty(tradeRecordList)){
            for (TradeRecord tradeRecord : tradeRecordList) {
                Integer tradeStatus = tradeRecord.getTradeStatus();
                if(tradeStatus != TradeStatusEnum.TRADE_STATUS_TRADING.getIndex()){
                    return UnfreezeCancelPayRespDTO.byFail(tradeVoucherNo, "交易业务单号已完成交易，请检查");
                }
            }
        }

        Integer draweeAccountStatus = draweeAccount.getStatus();
        if(draweeAccountStatus != AccountStatusEnum.VALID.getIndex()){
            return UnfreezeCancelPayRespDTO.byFail(tradeVoucherNo, "解冻账户状态异常");
        }

        return UnfreezeCancelPayRespDTO.bySuccess(tradeVoucherNo, "校验通过");
    }

}
